﻿using System.Collections.Generic;
using System.ServiceModel.Syndication;
using BusinessLogic.Models.Filter;
using Interfaces.FilterModels;
using Interfaces.Models;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System.Linq;

namespace DataProvidersUnitTest.NewsDataProviderTests
{
    
    [TestClass]
    public class SyndicationFilterTest
    {
        private readonly SyndicationFeed fakeData = MockDataProvider.MockNewsFeed;

        private const int ReturnCount = 2;

        [TestMethod]
        public void Filtrate_ByTitle_FillterSuccessApply()
        {
            const string titlePrefix = "test";
            var model = new Mock<INewsFilterModel>();
            model.Setup(x => x.Title).Returns(titlePrefix);
            var target = new SyndicationItemsFilter(model.Object);
            var actualList = target.Filtrate(fakeData.Items) as IEnumerable<SyndicationItem>;
            Assert.IsNotNull(actualList);
            Assert.AreEqual(ReturnCount,actualList.Count());
            Assert.IsTrue(actualList.All(item => item.Title.Text.StartsWith(titlePrefix)) || !actualList.Any());
        }

        [TestMethod]
        public void Filtrate_BySummary_FilterSuccessApply()
        {
            const string summaryContains = "sumTest";
            var model = new Mock<INewsFilterModel>();
            model.Setup(x => x.Summary).Returns(summaryContains);
            var target = new SyndicationItemsFilter(model.Object);
            var actualList = target.Filtrate(fakeData.Items) as IEnumerable<SyndicationItem>;
            Assert.IsNotNull(actualList);
            Assert.AreEqual(ReturnCount, actualList.Count());
            Assert.IsTrue(actualList.All(item=>item.Summary.Text.Contains(summaryContains)) || !actualList.Any());
        }

        [TestMethod]
        public void Filtrate_ByBaseUri_FilterSuccessApply()
        {
            const string baseUriHostPrefix = "baseUriTest";
            var model = new Mock<INewsFilterModel>();
            model.Setup(x => x.BaseUri).Returns(baseUriHostPrefix);
            var target = new SyndicationItemsFilter(model.Object);
            var actualList = target.Filtrate(fakeData.Items) as IEnumerable<SyndicationItem>;
            Assert.IsNotNull(actualList);
            Assert.IsTrue(actualList.All(item => item.BaseUri.Host.StartsWith(baseUriHostPrefix)) || !actualList.Any());
        }

        [TestMethod]
        public void Filtrate_ByAuthors_FilterSuccessApply()
        {
            var firstExcludedMockAuthor = CreatePersonMockObject(null, "testExcluded@mail", null);
            var secondExcludedMockAuthor = CreatePersonMockObject(null, "testExcluded@mail2", null);

            var model = new Mock<INewsFilterModel>();
            model.Setup(x => x.ExcludedAuthors).Returns(new List<IPerson>
                        {
                            firstExcludedMockAuthor.Object,
                            secondExcludedMockAuthor.Object
                        });
            var target = new SyndicationItemsFilter(model.Object);

            var actualList = target.Filtrate(fakeData.Items);
            Assert.IsNotNull(actualList);
            Assert.AreEqual(ReturnCount, actualList.Count());
        }

        [TestMethod]
        public void Filtrate_ByAuthorsExcludeAllItemsWithAutors_FilterSuccessApply()
        {
            var firstExcludedMockAuthor = CreatePersonMockObject(null, null, null);
            var model = new Mock<INewsFilterModel>();
            model.Setup(x => x.ExcludedAuthors).Returns(new List<IPerson>
                        {
                            firstExcludedMockAuthor.Object
                        });
            var target = new SyndicationItemsFilter(model.Object);

            var actualList = target.Filtrate(fakeData.Items) as IEnumerable<SyndicationItem>;
            Assert.IsNotNull(actualList);
            Assert.AreEqual(ReturnCount, actualList.Count());
            Assert.IsTrue(actualList.All(item=>item.Authors.Count==0));
        }

        [TestMethod]
        public void Filtrate_ByCategory_FilterSuccessApply()
        {
            var frstMockCategory = CreateCategoryMockObject("FirstTest",null);
            var secondMockCategory = CreateCategoryMockObject("SecondTest", null);

            var model = new Mock<INewsFilterModel>();
            model.Setup(x => x.ExcludedeCategory).Returns(new List<ICategory>
                        {
                            frstMockCategory.Object,
                            secondMockCategory.Object
                        });
            var target = new SyndicationItemsFilter(model.Object);

            var actualList = target.Filtrate(fakeData.Items) as IEnumerable<SyndicationItem>;
            Assert.IsNotNull(actualList);
            Assert.AreEqual(ReturnCount, actualList.Count());
        }

        private static Mock<IPerson> CreatePersonMockObject(string name, string email, string uri)
        {
            return new Mock<IPerson>().SetupProperty(prop => prop.Email, email)
                                      .SetupProperty(prop => prop.Name, name)
                                      .SetupProperty(prop => prop.Uri, uri);
        }

        private static Mock<ICategory> CreateCategoryMockObject(string name, string lable)
        {
            return new Mock<ICategory>().SetupProperty(prop => prop.Name, name).SetupProperty(prop => prop.Lable, lable);
        }

    }
}
